using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Inventory{
	
	/// <summary>
	/// Esta matrix representa los slots del inventario, 
	/// Tiene una referencia al item que lo ocupa.
	/// </summary>
	private Item[,] slots;
	/// <summary>
	/// Esta matrix representa la visual de los slots del inventario, 
	/// </summary>
	private GameObject[,] slotsVisual;
	/// <summary>
	/// Esta es la lista de items que contiene el inventario.
	/// </summary>
	private List<Item> itemsList;
	/// <summary>
	/// Este array se usa para escribir los valores donde se va a equipar el item que 
	/// se está chequeando. Lo hago asi para no tener que usar un parametro out y mierda.
	/// </summary>
	private int[] nextIndexForEquip;
	/// <summary>
	/// Se usa para controlar el drag de un item.
	/// </summary>
	public Item itemBeingDragged;
	
	public float slotscaleX;
	public float slotscaleY;
	public Inventory () : this(10,10){
	}
	/// <summary>
	/// Inicializar con los valores: ancho,alto que se quiere para el inventario.
	/// </summary>
	public Inventory (int rows, int cols) 
	{
		//Inicializar con los valores: ancho,alto que se quiere para el inventario.
		slots = new Item[rows,cols]; 
		slotsVisual = new GameObject[rows,cols];
		itemsList = new List<Item>();
		nextIndexForEquip = new int [2]{-1,-1};
		itemBeingDragged = null;
		slotscaleX = 0;
		slotscaleY = 0;
		
	}
	
	private void ClearSlots(){
		FillSlots(0,0,slots.GetLength(0),slots.GetLength(1),null );
	}
	/// <summary>
	/// Llena los slots de principio a fin, según se le pasa por parámetro, con el valor
	/// enviado al final.
	/// </summary>
	private void FillSlots(int startRow, int startCol, int endRow, int endCol, Item item){
		for (int row=startRow; row<endRow; row++){
			for (int col=startCol; col<endCol; col++){
				slots[row,col] = item;	
			}
		}
	}
	/// <summary>
	/// Se fija si el item que se quiere poner en el inventario entra.
	/// Si devuelve true, tambien setea el atributo this.nextIndexForEquip con los indices
	/// a partir de donde se tiene que equipar el item (row, col iniciales)
	/// </summary>
	/// <param name='itemMatrix'>
	/// La matriz del item que dice cuandos slots ocupa.
	/// </param>
	private bool CanStockItem(bool[,] itemMatrix){
		for (int row=0; row < slots.GetLength(0); row++){
			for (int col=0; col<slots.GetLength(1); col++){
				if (slots[row,col] == null){
					int endRow = row + itemMatrix.GetLength(0);
					int endCol = col + itemMatrix.GetLength(1);
				
					if ( CheckForSpaceNeeded(row,col,endRow,endCol) ){
						nextIndexForEquip[0] = row;
						nextIndexForEquip[1] = col;
						return true;
					}
				}
			}
		}
		nextIndexForEquip[0] = -1;
		nextIndexForEquip[1] = -1;
		return false;
	}
	/// <summary>
	/// Verifica si se puede meter el item entre los indices especificados.
	/// </summary>
	private bool CheckForSpaceNeeded(int startRow, int startCol, int endRow, int endCol){
		if (endRow>slots.GetLength(0) || endCol>slots.GetLength(1) )
			return false;
					
		for (int row=startRow; row<endRow; row++){
			for (int col=startCol; col<endCol; col++){
				if (slots[row,col] != null)
					return false;
			}
		}
		return true;
	}
	
	private bool MoveItemTo(Item item, int row, int col){
		//Limpio la posición actual
		FillSlots(item.GetIndexInInventory(0), item.GetIndexInInventory(1),
			item.GetIndexInInventory(0) + item.GetSpaceMatrix().GetLength(0),
			item.GetIndexInInventory(1) + item.GetSpaceMatrix().GetLength(1), null);
			
		if (CanStockItemAt(item.GetSpaceMatrix(),row,col ) ){
			nextIndexForEquip[0] = row;
			nextIndexForEquip[1] = col;
			
			//Si puedo guardar el item lleno la posición nueva.
			FillSlots(row, col,
				row + item.GetSpaceMatrix().GetLength(0),
				col + item.GetSpaceMatrix().GetLength(1), item);
			item.SetPlaceInInventory(row,col);
			Debug.Log("New Slot: " +row+" "+col );
			//LocateItemVisualAtStockedPosition(item);
			return true;
		}
		nextIndexForEquip[0] = item.GetIndexInInventory(0);
		nextIndexForEquip[1] = item.GetIndexInInventory(1);
		//Si no puedo mover el item vuelvo a ponerlo donde estaba al principio.
		FillSlots(item.GetIndexInInventory(0), item.GetIndexInInventory(1),
			item.GetIndexInInventory(0) + item.GetSpaceMatrix().GetLength(0),
			item.GetIndexInInventory(1) + item.GetSpaceMatrix().GetLength(1), item);
			
		return false;
	}
	private void LocateItemVisualAtStockedPosition(Item item){
    	GameObject slot = InventoryController.GetInstance()
		.GetActiveInventory().GetSlotVisual(
			nextIndexForEquip[0], nextIndexForEquip[1]);
		
        Transform t = slot.transform.parent;
        slotscaleX = slot.transform.localScale.x;
        slotscaleY = slot.transform.localScale.y;
		while (t.parent != null)
        {
            slotscaleX *= t.transform.localScale.x;
            slotscaleY *= t.transform.localScale.y;
            t = t.parent;
        }
		        
        item.transform.position = slot.transform.position + Vector3.left * slotscaleX / 2.0f + Vector3.up * slotscaleY / 2.0f;
		item.transform.position += Vector3.right * (item.transform.localScale.x * item.visualModelGUI.transform.localScale.x)/2.0f;
        item.transform.position += Vector3.down * (item.transform.localScale.y * item.visualModelGUI.transform.localScale.y)/2.0f;
		item.transform.position += Vector3.back/10;
	}
	private void ResizeItemToPanel(Item item){
		item.transform.localScale = 
			InventoryController.GetInstance().GetGUIPanel().ResizeScaleToFitPanel(item.transform.localScale);
		item.wasResizedToFitPanel = true;
	}
	public void ReturnItemToOriginalPosition(Item item){
		item.OnClic(Vector3.zero);
		//Limpio la posición actual
		FillSlots(item.GetIndexInInventory(0), item.GetIndexInInventory(1),
			item.GetIndexInInventory(0) + item.GetSpaceMatrix().GetLength(0),
			item.GetIndexInInventory(1) + item.GetSpaceMatrix().GetLength(1), null);
			
		nextIndexForEquip[0] = item.GetIndexInInventory(0);
		nextIndexForEquip[1] = item.GetIndexInInventory(1);
		//Si no puedo mover el item vuelvo a ponerlo donde estaba al principio.
		FillSlots(item.GetIndexInInventory(0), item.GetIndexInInventory(1),
			item.GetIndexInInventory(0) + item.GetSpaceMatrix().GetLength(0),
			item.GetIndexInInventory(1) + item.GetSpaceMatrix().GetLength(1), item);
		
		LocateItemVisualAtStockedPosition(item);
		itemBeingDragged = null;
	}
	public bool CanStockItemAt(bool[,] itemMatrix, int startRow, int startCol){
		return CheckForSpaceNeeded(startRow, startCol, 
			startRow+itemMatrix.GetLength(0), startCol+itemMatrix.GetLength(1) );
	}	
	public Item GetItemInSlot(int row, int col){ 
		return slots[row,col];
	}
	
	/// <summary>
	/// Si entra, lo guarda en el inventario en la primer posición libre que encuentre.
	/// </summary>
	/// <returns>
	/// True si hay lugar y lo guardó.
	/// </returns>
	/// <param name='item'>
	/// El item para guardar.
	/// </param>
	public bool StockItem(Item item){
		if (CanStockItem(item.GetSpaceMatrix() ) )
        {

			itemsList.Add(item);
			FillSlots(nextIndexForEquip[0], nextIndexForEquip[1],
					nextIndexForEquip[0] + item.GetSpaceMatrix().GetLength(0),
					nextIndexForEquip[1] + item.GetSpaceMatrix().GetLength(1), item );
			
			item.SetPlaceInInventory(nextIndexForEquip[0],nextIndexForEquip[1] );
			item.ShowModelWorld(false);
			item.ShowModelGUI(true);

 
            item.gameObject.SetActive(false);

			if (!item.wasResizedToFitPanel)
            {
				ResizeItemToPanel(item);	
			}
            if (item.m_Holder != null)
            {
                item.m_Holder.m_AvailableLoot = null;
            }
			LocateItemVisualAtStockedPosition(item);
			Debug.LogWarning("Stocked Item: " + item + "At slot: " + nextIndexForEquip[0] +","+ nextIndexForEquip[1]); 
			return true;
		}
		return false;
	}	
	public void DropItem(Item item){
		if (itemsList.Contains(item) ){
			itemsList.Remove(item);
			FillSlots(item.GetIndexInInventory(0), item.GetIndexInInventory(1),
				item.GetIndexInInventory(0)+item.GetSpaceMatrix().GetLength(0),
				item.GetIndexInInventory(1)+item.GetSpaceMatrix().GetLength(1), null);
			item.SetPlaceInInventory(-1,-1);
		}
		MouseController.instance.drawCursor = true;
        item.OnDrop();
       	item.transform.parent = null;
		item.transform.position = Player.instance.GetSelectedCharacterTransform().position;
		item.ShowModelWorld(true);
		item.ShowModelGUI(false);

        item.wasResizedToFitPanel = false;

		item.transform.localScale = item.originalScale;
		item.isBeingDragged = false;
		itemBeingDragged = null;
	}
    public void RemoveFromInventory(Item item)
    {
        if (itemsList.Contains(item))
        {
            itemsList.Remove(item);
            FillSlots(item.GetIndexInInventory(0), item.GetIndexInInventory(1),
                item.GetIndexInInventory(0) + item.GetSpaceMatrix().GetLength(0),
                item.GetIndexInInventory(1) + item.GetSpaceMatrix().GetLength(1), null);
            item.SetPlaceInInventory(-1, -1);

            item.transform.parent = null;
            item.isBeingDragged = false;
            item.transform.localScale = item.originalScale;

            item.ShowModelWorld(false);
            item.ShowModelGUI(false);
        }
    }
	public void DropDraggedItem(){
		DropItem(itemBeingDragged);	
	}
	public int GetRowsCount(){return slots.GetLength(0);}
	public int GetColumnsCount(){return slots.GetLength(1);}
	public GameObject GetSlotVisual(int row, int col){
		return slotsVisual[row,col];	
	}
	public void SetSlotVisual(int row, int col, GameObject slot){
		slotsVisual[row,col] = slot;
	}
	public void OnClic(int row, int col){
		if (itemBeingDragged == null){
			itemBeingDragged = GetItemInSlot(row, col);
			if (itemBeingDragged == null)
				return;
			itemBeingDragged.OnClic(Vector3.zero);	
		} else{
			itemBeingDragged.OnClic(Vector3.zero);
			//if (!MoveItemTo(itemBeingDragged, row, col) )
			MoveItemTo(itemBeingDragged, row, col);
			LocateItemVisualAtStockedPosition(itemBeingDragged);
			itemBeingDragged = null;
		}
	}
	public void OnClicOutside(){
		if (itemBeingDragged != null)
			DropDraggedItem();
	}
	public List<Item> GetItemsList(){ return this.itemsList;}
}
